package grpcserver

import (
	"context"
	"fmt"
	"log"
	"net"
	"time"

	"chat.com/common"
	"chat.com/register"
	pb "chat.com/server/grpc/protobuf"
	"chat.com/server/wsserver/service"
	"chat.com/setting"
	"google.golang.org/grpc/keepalive"
	"google.golang.org/protobuf/proto"

	"google.golang.org/grpc"
)

type server struct {
	pb.UnimplementedAccServerServer
}

func setErr(rsp proto.Message, code int64, message string) {

	message = common.GetErrorMessage(code, message)

	switch v := rsp.(type) {
	case *pb.QueryUsersOnlineRsp:
		v.RetCode = code
		v.ErrMsg = message
	case *pb.SendSingleMsgRsp:
		v.RetCode = code
		v.ErrMsg = message
	case *pb.SendSystemMsgRsp:
		v.RetCode = code
		v.ErrMsg = message
	case *pb.GetUserListRsp:
		v.RetCode = code
		v.ErrMsg = message
	default:
	}

}

// 查询用户是否在线
func (s *server) QueryUsersOnline(c context.Context,
	req *pb.QueryUsersOnlineReq) (rsp *pb.QueryUsersOnlineRsp, err error) {

	fmt.Println("grpc_request 查询用户是否在线", req.String())
	rsp = &pb.QueryUsersOnlineRsp{}
	isOnline := service.IsUserOnline(req.GetAppId(), req.GetUserId())
	setErr(rsp, common.OK, "")
	rsp.Online = isOnline
	return rsp, nil
}

// 给本机用户发单聊消息
func (s *server) SendSingleChatMsg(c context.Context, req *pb.SendSingleMsgReq) (rsp *pb.SendSingleMsgRsp, err error) {

	fmt.Println("grpc_request 给本机用户发消息", req.String())

	rsp = &pb.SendSingleMsgRsp{}

	if req.GetIsLocal() {
		// 不支持
		setErr(rsp, common.ParameterIllegal, "")
		return
	}

	msg := &common.WsSingleChatRequest{
		//Id:         req.Id,
		AppId:      req.AppId,
		Type:       req.Type,
		Content:    req.Content,
		SenderId:   req.SenderId,
		RecieverId: req.RecieverId,
		SentTime:   req.SentTime,
	}

	sendResult, err := service.SendSingleChatMessageLocal(msg)

	if err != nil {
		fmt.Println("系统错误", err)
		setErr(rsp, common.ServerError, "")
		return rsp, nil
	}

	if !sendResult {
		fmt.Println("发送失败", err)
		setErr(rsp, common.OperationFailure, "")
		return rsp, nil
	}

	setErr(rsp, common.OK, "")

	fmt.Println("grpc_response 给本机用户发消息", rsp.String())
	return
}

// 给本机用户发群聊消息
func (s *server) SendGroupChatMsg(c context.Context, req *pb.SendGroupMsgReq) (rsp *pb.SendGroupMsgRsp, err error) {

	fmt.Println("grpc_request 给本机用户发消息", req.String())

	rsp = &pb.SendGroupMsgRsp{}

	if req.GetIsLocal() {
		// 不支持
		setErr(rsp, common.ParameterIllegal, "")
		return
	}

	msg := &common.WsGroupChatRequest{
		//Id:         req.Id,
		AppId:      req.AppId,
		Type:       req.Type,
		Content:    req.Content,
		SenderId:   req.SenderId,
		RecieverId: req.RecieverId,
		SentTime:   req.SentTime,
	}

	sendResult, err := service.SendGroupChatMessageLocal(msg)

	if err != nil {
		fmt.Println("系统错误", err)
		setErr(rsp, common.ServerError, "")
		return rsp, nil
	}

	if !sendResult {
		fmt.Println("发送失败", err)
		setErr(rsp, common.OperationFailure, "")
		return rsp, nil
	}

	setErr(rsp, common.OK, "")

	fmt.Println("grpc_response 给本机用户发消息", rsp.String())
	return
}

// 给本机全体用户发消息
/*
func (s *server) SendMsgAllUser(c context.Context, req *pb.SendMsgAllReq) (rsp *pb.SendMsgAllRsp, err error) {

	fmt.Println("grpc_request 给本机全体用户发消息", req.String())

	rsp = &pb.SendMsgAllRsp{}

	data := model.GetTextMsgData(
		req.GetAppId(), req.GetType(), req.GetMsg(), req.GetSenderId(), 0, req.GetSentTime(),
	)

	wsServer.AllSendMessages(req.GetAppId(), req.GetSenderId(), data)

	setErr(rsp, common.OK, "")

	fmt.Println("grpc_response 给本机全体用户发消息:", rsp.String())
	return
}*/

// 获取本机用户列表
func (s *server) GetUserList(c context.Context, req *pb.GetUserListReq) (rsp *pb.GetUserListRsp, err error) {
	fmt.Println("grpc_request 获取本机用户列表", req.String())
	appId := req.GetAppId()
	rsp = &pb.GetUserListRsp{}

	userList, userCount := service.AllUsers(appId)
	setErr(rsp, common.OK, "")
	rsp.UserId = userList
	rsp.UserCount = int64(userCount)
	fmt.Println("grpc_response 获取本机用户列表:", rsp.String())
	return
}

// rpc server
func Init() {

	// 程序退出时删除grpc服务
	defer register.ServerRegisterInstance.DelNode(
		setting.ZookeeperSetting.RpcServerCenter,
		setting.RpcServerSetting.Name,
	)

	rpcAddr := setting.RpcServerSetting.Host
	fmt.Println("rpc server 启动", rpcAddr)

	lis, err := net.Listen("tcp", rpcAddr)
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}

	var kaep = keepalive.EnforcementPolicy{
		MinTime:             15 * time.Minute, // If a client pings more than once every 5 seconds, terminate the connection
		PermitWithoutStream: true,             // Allow pings even when there are no active streams
	}

	var kasp = keepalive.ServerParameters{
		MaxConnectionIdle:     15 * time.Minute, // If a client is idle for 15 seconds, send a GOAWAY
		MaxConnectionAge:      30 * time.Minute, // If any connection is alive for more than 30 seconds, send a GOAWAY
		MaxConnectionAgeGrace: 5 * time.Minute,  // Allow 5 seconds for pending RPCs to complete before forcibly closing connections
		Time:                  5 * time.Minute,  // Ping the client if it is idle for 5 seconds to ensure the connection is still active
		Timeout:               1 * time.Minute,  // Wait 1 second for the ping ack before assuming the connection is dead
	}

	s := grpc.NewServer(grpc.KeepaliveEnforcementPolicy(kaep), grpc.KeepaliveParams(kasp))
	pb.RegisterAccServerServer(s, &server{})

	// 注册grpc服务
	register.ServerRegisterInstance.RegisterNode(
		setting.ZookeeperSetting.RpcServerCenter, setting.RpcServerSetting.Name, setting.RpcServerSetting.Host,
	)

	if err := s.Serve(lis); err != nil {
		log.Fatalf("failed to serve: %v", err)
	}
}
